/**
 * VUE的基本原理： by liuxf
 * 1、建立虚拟DOM Tree，通过document.createDocumentFragment()，遍历指定根节点内部节点，
 * 根据{{ prop }}、v-model等规则进行compile；
 *
 2、通过Object.defineProperty()进行数据变化拦截；

 3、截取到的数据变化，通过发布者-订阅者模式，触发Watcher，从而改变虚拟DOM中的具体数据；

 4、通过改变虚拟DOM元素值，从而改变最后渲染dom树的值，完成双向绑定
 完成数据的双向绑定在于Object.defineProperty()
 */

var MVVM = function(options){
    this.$data = options.data;
    this.$el = options.el;
    this._proxy(options.data);
    this._proxy(options.methods);
    var ob = observer(this.$data);
    if(!ob) return;
    compile(options.el,this);
};
/*
comment by liuxf:
1. 监听器Observer
2. 订阅者Watcher
3. 消息订阅器Dep
4. 指令解析器Compile

首先要设置一个监听器Observer,用来监听所有的属性，当属性变化时，就需要通知订阅者Watcher,看是否需要更新．
因为属性可能是多个，所以会有多个订阅者，故我们需要一个消息订阅器Dep来专门收集这些订阅者，
并在监听器Observer和订阅者Watcher之间进行统一的管理．
在节点元素上可能存在一些指令，所以还需要有一个指令解析器Compile，对每个节点元素进行扫描和解析，
将相关指令初始化成一个订阅者Watcher，并替换模板数据并绑定相应的函数，这时候当订阅者Watcher接受到相应属性的变化，
就会执行相对应的更新函数，从而更新视图．
* */
MVVM.prototype._proxy = function(data){
    //添加
    var self = this;
    for(var key in data) {
        (function(key){
            Object.defineProperty(self,key,{
                get:function(){
                    //Watcher中使用这种方式触发自定义的get，所以_proxy需要在Compile之前调用
                    return data[key];
                },
                set:function(newVal){
                    data[key] = newVal;
                }
            })
        })(key);

    }

};